package com.atguigu.service.impl;

import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.CartInfoService;
import com.atguigu.util.AuthContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author zhangqiang
 * @since 2022-09-08
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoServiceImpl asyncCartInfoServiceImpl;

    @Override
    public void addToCart(String oneOfUserId, Long skuId, Integer skuNum) {
        //先查询数据库是否有该购物车信息
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        wrapper.eq("sku_id", skuId);
        CartInfo existCartInfo = baseMapper.selectOne(wrapper);
        //如果有数据 把传递过来的数量+购物车已有数量
        if (existCartInfo != null) {
            existCartInfo.setSkuNum(existCartInfo.getSkuNum() + skuNum);
            //更新购物车实时价格
            existCartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
        } else {
            //如果没有数据 则在数据库添加购物车数据
            existCartInfo = new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            existCartInfo.setUserId(oneOfUserId);
            existCartInfo.setSkuId(skuId);
            existCartInfo.setCartPrice(skuInfo.getPrice());
            existCartInfo.setSkuNum(skuNum);
            existCartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            existCartInfo.setSkuName(skuInfo.getSkuName());
            existCartInfo.setIsChecked(1);
            existCartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            baseMapper.insert(existCartInfo);
            //添加redis缓存  user:3:cart
            String userCartKey = getUserCartKey(oneOfUserId);
            redisTemplate.boundHashOps(userCartKey).put(skuId.toString(), existCartInfo);
        }

    }

    //购物车列表
    @Override
    public List<CartInfo> getCartList(HttpServletRequest request) {
        String userTempId = AuthContextHolder.getUserTempId(request);
        String userId = AuthContextHolder.getUserId(request);
        List<CartInfo> cartInfoList = new ArrayList<>();
        //未登录的
        if (StringUtils.isEmpty(userId) && !StringUtils.isEmpty(userTempId)) {
            cartInfoList = queryCartInfoFromDbToRedis(userTempId);
        }
        //已登录
        if (!StringUtils.isEmpty(userId) && !StringUtils.isEmpty(userTempId)) {
            //查询所有未登录的购物车项
            List<CartInfo> noLoginCartInfoList = queryCartInfoFromDbToRedis(userTempId);
            if (!StringUtils.isEmpty(noLoginCartInfoList)) {
                //合并登录与未登录的购物车项
                mergeCartInfoList(userId,userTempId);
                //删除临时购物车项
                deleteOldData(userId,userTempId);
            }else {
                //未登录的信息为空
                String userCartKey = getUserCartKey(userId);
                redisTemplate.delete(userCartKey);
            }
            //重新加载数据到缓存
            cartInfoList = queryCartInfoFromDbToRedis(userId);
        }
        return cartInfoList;
    }

    //3.购物车列表勾选
    @Override
    public void checkCart(String oneOfUserId, Long skuId, Integer isChecked) {
        //从数据库中查询并修改
        asyncCartInfoServiceImpl.checkDbCart(oneOfUserId, skuId, isChecked);
        //从redis中查询数据并修改
        String userCartKey=getUserCartKey(oneOfUserId);
        BoundHashOperations operations = redisTemplate.boundHashOps(userCartKey);
        //看redis中是否有该商品信息
        if (operations.hasKey(skuId.toString())) {
            CartInfo redisCartInfo = (CartInfo) operations.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //跟新到redis中
            operations.put(skuId.toString(), redisCartInfo);
            setCartKeyExpire(userCartKey);
        }
    }

    //4.购物车项删除
    @Override
    public void deleteCart(String oneOfUserId, Long skuId) {
        //删除缓存
        String userIdCartKey=getUserCartKey(oneOfUserId);
        BoundHashOperations operations = redisTemplate.boundHashOps(userIdCartKey);
        //看redis中是否有该商品信息
        if (operations.hasKey(skuId.toString())){
            operations.delete(skuId.toString());
        }
        //删除数据库
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",oneOfUserId);
        wrapper.eq("sku_id",skuId);
        baseMapper.delete(wrapper);
    }

    //5.购物车项生成订单
    @Override
    public List<CartInfo> getSelectedCartInfo(String userId) {
        String userCartKey = getUserCartKey(userId);
        List<CartInfo> redisCartInfoList = redisTemplate.opsForHash().values(userCartKey);
        List<CartInfo> selectedCartInfo=new ArrayList<>();
        if (!CollectionUtils.isEmpty(redisCartInfoList)){
            for (CartInfo cartInfo : redisCartInfoList) {
                if (cartInfo.getIsChecked()==1){
                    selectedCartInfo.add(cartInfo);
                }
            }
        }
        return selectedCartInfo;
    }

    private void deleteOldData(String userId, String userTempId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userTempId);
        baseMapper.delete(wrapper);
        //删除缓存
        String userIdCartKey=getUserCartKey(userId);
        String userTempIdCartKey=getUserCartKey(userTempId);
        redisTemplate.delete(userIdCartKey);
        redisTemplate.delete(userTempIdCartKey);

    }

    private void mergeCartInfoList(String userId, String userTempId) {
        //未登录
        List<CartInfo> noLoginCartInfoList = queryCartInfoFromDbToRedis(userTempId);
        //已登录
        List<CartInfo> loginCartInfoList = queryCartInfoFromDbToRedis(userId);
        //把已登录的放入map中
        Map<Long, CartInfo> loginCartInfoMap = loginCartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
            Long skuId = noLoginCartInfo.getSkuId();
            //对比skuId是否相同 如果相同代表登录项有该购物项
            if (loginCartInfoMap.containsKey(skuId)) {
                CartInfo loginCartInfo = loginCartInfoMap.get(skuId);
                //对数量进行相加操作
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+noLoginCartInfo.getSkuNum());
                //更新数据库
                baseMapper.updateById(loginCartInfo);
            }else {
                //如果购物项中没有该购物项
                noLoginCartInfo.setUserId(userId);
                baseMapper.updateById(noLoginCartInfo);
            }
        }
    }

    private List<CartInfo> queryCartInfoFromDbToRedis(String oneOfUserId) {
        String userCartKey = getUserCartKey(oneOfUserId);
        List<CartInfo> cartInfoList = redisTemplate.boundHashOps(userCartKey).values();
        //判断缓存中有没有,没有值进去数据库查询
        if (CollectionUtils.isEmpty(cartInfoList)) {
            QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", oneOfUserId);
            cartInfoList = baseMapper.selectList(wrapper);
            //往redis存
            Map<String, Object> cartInfoMap = new HashMap<>();
            for (CartInfo cartInfo : cartInfoList) {
//                redisTemplate.boundHashOps(userCartKey).put(cartInfo.getSkuId().toString(),cartInfo);
                cartInfoMap.put(cartInfo.getSkuId().toString(), cartInfo);
            }
            redisTemplate.boundHashOps(userCartKey).putAll(cartInfoMap);
            //购物车信息设置一个过期时间
            setCartKeyExpire(userCartKey);
        }
        return cartInfoList;
    }

    //购物车信息过期时间
    private void setCartKeyExpire(String userCartKey) {
        redisTemplate.expire(userCartKey, RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

    private String getUserCartKey(String oneOfUserId) {
        return RedisConst.USER_KEY_PREFIX + oneOfUserId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
